package core

import (
	"errors"
	"fmt"
	errors2 "github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"hpmGo/constants"
	"hpmGo/utils"
	"os"
	"path/filepath"
	"sync"
)

type Bundle struct {
	Manifest
	BundlePath string
}

func init() {
	logrus.SetFormatter(&logrus.TextFormatter{
		DisableColors: true,
		FullTimestamp: true,
	})
}

func (b *Bundle) SaveManifestToJson() error {
	err := b.SaveToJson(b.BundlePath)
	if err != nil {
		return err
	}
	return nil
}

func (b Bundle) Resolve(repo Repo) (manifests []Manifest, err error) {
	for name := range b.Dependencies {
		var manifest Manifest
		manifest, err = repo.Manifest(name, b.Dependencies[name])
		if err != nil {
			err = errors2.Errorf("resove dependency %s - %s failed", name, b.Dependencies[name])
			return
		}
		manifests = append(manifests, manifest)
	}
	return
}

func (b Bundle) Install(repo Repo) error {
	var wg sync.WaitGroup
	manifests, err := b.Resolve(repo)
	if err != nil {
		return err
	}
	installPath, err := os.Getwd()
	if err != nil {
		return errors2.WithMessage(err, "Install: get cwd failed")
	}
	for _, manifest := range manifests {
		if manifest.Url == "" {
			logrus.Infof("%s has already exist", manifest.Name)
			continue
		}
		logrus.Infof("Downloading: %s", manifest.Name)
		wg.Add(1)
		go DownloadManifest(manifest, installPath, &wg)
		wg.Wait()
		logrus.Infof("Downloaded: %s", manifest.Name)
	}
	return nil
}

func FromDir(path string) (bundle Bundle, err error) {
	bundleJsonDir := filepath.Join(path, "bundle.json")
	m, err := FromBundleJson(bundleJsonDir)
	if err != nil {
		return Bundle{}, errors.New("FromDir error: json parse failed")
	}
	bundle = Bundle{BundlePath: path, Manifest: m}
	return
}

func DownloadManifest(manifest Manifest, installPath string, wg *sync.WaitGroup) error {
	defer wg.Done()
	// 创建目录
	scope, name := ParseScopeName(manifest.Name)
	manifestDirPath := filepath.Join(installPath, constants.OHOS_BUNDLES, scope, name)
	err := os.MkdirAll(manifestDirPath, 0666)
	if err != nil {
		return errors2.WithMessage(err, "DownloadManifest: mkdir failed")
	}
	filename := fmt.Sprintf("%s-%s.tgz", name, manifest.Version)
	manifestTgzPath := filepath.Join(manifestDirPath, filename)
	// 下载压缩包到指定目录
	err = manifest.Install(manifestTgzPath)
	// 解压压缩包
	file, err := os.Open(manifestTgzPath)
	if err != nil {
		return errors2.WithMessage(err, "DownloadManifest: open tgz failed")
	}
	err = utils.Extract(file, manifestDirPath)
	file.Close()
	if err != nil {
		return errors2.WithMessage(err, "DownloadManifest: extract tgz failed")
	}
	// 删除压缩包
	os.Remove(manifestTgzPath)
	//
	err = manifest.CopySegment()
	if err != nil {
		return err
	}
	return nil
}
